package org.noahsark.core.dao;

import java.io.Serializable;
import java.util.List;

import javax.persistence.EntityManager;

import org.hibernate.Session;
import org.noahsark.core.domainmodel.BaseEntity;
import org.noahsark.core.jpa.util.JpaUtil;

public class JpaEntityManagerDao/*<BaseEntity<Serializable>, Serializable>*/ 
<E extends BaseEntity<K>, K extends Serializable>
extends BaseDao<BaseEntity<Serializable>, Serializable>{

	/**
     * 按类型和主键查询实体.
     * 
     * @param <T> t
     * @param clazz 实体类
     * @param id 主键
     * @return <T> t 查询到的实体，如果没有查询到就返回null
     */
	@Override
	public <T> T find(Class<T> clazz, Serializable id) {
		log.info("method findById in class JpaEntityManagerDao begin");
		
		T t = getEm().find(clazz, id);
		
		log.info("method findById in class JpaEntityManagerDao end");
		
		return t;
	}

	/**
     * 按主键查询实体.
     * 
     * @param refresh true:从数据库查询，false:如果EntityManager中有直接使用，
     * 可能 会导致查询出的实体与数据库不一致。
     * @param id 实体主键
     * @return E 查询到的实体，如果没有查询到就返回null
     */
	@Override
	public BaseEntity<Serializable> findById(Serializable id, boolean refresh) {
		log.info("method findById in class JpaEntityManagerDao begin");
        
        final Class<BaseEntity<Serializable>> productClass = this.getEntityClass();
        BaseEntity<Serializable> baseEntity = this.getEm().find(productClass, id);
        if (refresh) {
            log.info("refreshing loaded entity");
            // refresh(Object entity):Refresh the state of the instance from the database, overwriting changes made to the entity, if any.
            getEm().refresh(baseEntity); 
        }
        
        log.info("method findById in class JpaEntityManagerDao begin");
        
        return baseEntity;
	}

	/**
     * 用于创建其它类型的实体，不受泛型限制，不会增加审计信息.
     * 
     * @param entity 要创建的实体
     */
	@SuppressWarnings("unchecked")
	@Override
	public BaseEntity<Serializable> persist(Object entity) {
		log.info("method persist in class JpaEntityManagerDao begin");
    	
        this.getEm().persist(entity);
        
        log.info("method persist in class JpaEntityManagerDao end");
        
        return (BaseEntity<Serializable>) entity;
	}

	/**
     * 创建单实体，给实体增加审计信息. 创建复合实体需要在子类重写（这个方法暂时与persist方法功能相同）
     * 
     * @param entity E
     */
	@Override
	public BaseEntity<Serializable> create(BaseEntity<Serializable> entity) {
		log.info("method create in class JpaEntityManagerDao begin");

		this.getEm().persist(entity);
		BaseEntity<Serializable> newEntity = entity;
		
		log.info("method create in class JpaEntityManagerDao end");
		
		return newEntity;
	}

	/**
     * 直接删除实体，不受泛型限制.
     * 
     * @param entity 要删除的实体
     */
	@Override
	public void remove(Object entity) {
		log.info("method remove in class JpaEntityManagerDao begin");
		
		this.getEm().remove(entity);
		
		log.info("method remove in class JpaEntityManagerDao end");
	}

	/**
     * 直接删除实体.
     * 
     * @param entity 要删除的实体
     */
	@Override
	public void remove(BaseEntity<Serializable> entity) {
		log.info("method remove in class JpaEntityManagerDao begin");

        this.getEm().remove(entity);

        log.info("method remove in class JpaEntityManagerDao end");
	}

	/**
     * 更新单实体，给实体增加审计信息. 更新复合实体需要在子类重写.
     * 
     * @param entity 要更新的实体，可以是vo，也可以上po
     * @return E 返回实体，更新子实体时使用。
     */
	@Override
	public BaseEntity<Serializable> update(BaseEntity<Serializable> entity) {
		log.info("method update in class JpaEntityManagerDao begin");
		
		BaseEntity<Serializable> po = entity;

        if (!this.getEm().contains(entity)) {
            po = this.findById(entity.getId(), true);
            this.dataTransfer(entity, po);
        }
        this.updatePo(po);
        
        log.info("method update in class JpaEntityManagerDao end");
        
        return po;
	}

	/**
     * 查询所有的实体对象
     * 
     * @param cacheable
     * @return
     */
	@SuppressWarnings("unchecked")
	@Override
	protected List<BaseEntity<Serializable>> queryAll(boolean cacheable) {
		log.info("method queryAll in class JpaEntityManagerDao begin");
		
		final Class<? extends Serializable> entityClass = this.getEntityClass();
        QueryBuilder qb = new QueryBuilder("from " + entityClass.getName());
        
        log.info("method queryAll in class JpaEntityManagerDao end");
        
        if (cacheable) {
            return qb.find(getEm());
        } else {
            return qb.find(getEm());
        }
	}

	/**
     * dao中需要得到em.
     * 
     * @return EntityManager
     */
	@Override
	protected EntityManager getEm() {
		if (em != null) {
            return em;
        }
		return JpaUtil.currentEntityManager();
	}

	/**
     * dao中需要得到sn.
     * @return Session
     */
	@Override
	protected Session getSn() {
		// TODO Auto-generated method stub
		return null;
	}

	/**
     * query count querySingle3个方法只为子类服务.
     * 
     * 执行QueryBuilder查询，查询结果是list
     * 
     * @param queryBuilder queryBuilder
     * @return List<Object>
     */
	@SuppressWarnings("unchecked")
	@Override
	protected List<BaseEntity<Serializable>> query(QueryBuilder queryBuilder) {
		return (List<BaseEntity<Serializable>>) queryBuilder.find(this.getEm());
	}

	/**
     * queryVO for query object is VO.
     * 
     * return voList;
     * 
     * @param queryBuilder queryBuilder
     * @return List
     */
	@SuppressWarnings("unchecked")
	@Override
	protected List<BaseEntity<Serializable>> queryVO(QueryBuilder queryBuilder) {
		return (List<BaseEntity<Serializable>>)queryBuilder.find(getEm());
	}

	/**
     * 执行QueryBuilder查询.
     * 
     * @param queryBuilder queryBuilder
     * @return Long 查询总数
     */
	@Override
	protected Long count(QueryBuilder queryBuilder) {
		return queryBuilder.count(getEm());
	}

	/**
     * 执行QueryBuilder查询，查询单个实体.
     * 
     * @param queryBuilder queryBuilder
     * @return Object 单个实体，查询不到返回null
     */
	@SuppressWarnings("unchecked")
	@Override
	protected BaseEntity<Serializable> querySingle(QueryBuilder queryBuilder) {
		return (BaseEntity<Serializable>) queryBuilder.findSingle(this.getEm());
	}

	/**
     * 执行QueryBuilder查询，查询单个实体. forceReturnSingle is true, force return the first entity; otherwise
     * throw exception.
     * 
     * @param queryBuilder queryBuilder
     * @param forceReturnSingle boolean
     * @return Object 单个实体，查询不到返回null
     */
	@SuppressWarnings("unchecked")
	@Override
	protected BaseEntity<Serializable> querySingle(QueryBuilder queryBuilder,boolean forceReturnSingle) {
		if (forceReturnSingle) {
            List<BaseEntity<Serializable>> list = (List<BaseEntity<Serializable>>) queryBuilder.find(getEm());
            if (list.size() > 0) {
                return list.get(0);
            } else {
                return null;
            }
        }

        return (BaseEntity<Serializable>) queryBuilder.findSingle(getEm());
	}

	/**
     * batch execute update by JPQL or Native sql in QueryBuilder.
     * 
     * @param queryBuilder - QueryBuilder
     * @return the number of entities updated
     */
	@Override
	protected int batchUpdate(QueryBuilder queryBuilder) {
		return queryBuilder.batchUpdate(this.getEm());
	}

	
	

}
